package com.rambo.sdh.common.dao.impl;

import com.rambo.sdh.common.dao.inter.BaseDao;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * 数据库将会为只读事务提供一些优化手段，例如Oracle对于只读事务，不启动回滚段，不记录回滚log。
 * @param <T> 数据库对应实体 PO
 * @param <PK> 实体 PO 主键
 */
@SuppressWarnings("unchecked")
public class BaseDaoImpl<T, PK extends Serializable> implements BaseDao<T, PK> {

    private Class<T> entityClass;

    private SessionFactory sessionFactory;

    public BaseDaoImpl(SessionFactory sessionFactory) {
        this.entityClass = null;
        this.sessionFactory = sessionFactory;
        Class<?> c = getClass();
        Type type = c.getGenericSuperclass(); //反射获取超类
        if (type instanceof ParameterizedType) {
            Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
            this.entityClass = (Class<T>) parameterizedType[0];
        }
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    public T getByKey(PK id) {
        Assert.notNull(id, "id is required");
        return (T) getSession().get(entityClass, id);
    }

    public T add(T entity) {
        Assert.notNull(entity, "entity is required");
        getSession().save(entity);
        return entity;
    }

    public T edit(T entity) {
        Assert.notNull(entity, "entity is required");
        getSession().update(entity);
        return entity;
    }

    public T deleteByKey(PK id) {
        Assert.notNull(id, "id is required");
        T t = (T) getSession().load(entityClass, id);
        getSession().delete(t);
        return t;
    }

    public List<T> findByExample(T entity) {
        try {
            Criteria criteria = getSession().createCriteria(entity.getClass());
            criteria.add(Example.create(entity));
            return criteria.list();
        } catch (RuntimeException e) {
            throw e;
        }
    }

    public List<T> findByExample(T entity, Order order) {
        try {
            Criteria criteria = getSession().createCriteria(entity.getClass());
            if (order != null) {
                criteria.addOrder(order);
            }
            return criteria.add(Example.create(entity)).list();
        } catch (RuntimeException re) {
            throw re;
        }
    }

    public T getOneByExample(T entity) {
        try {
            List<T> list = findByExample(entity);
            if (list != null && list.size() > 0) {
                return list.get(0);
            }
            return null;
        } catch (RuntimeException re) {
            throw re;
        }
    }

    public T getOneByExample(T entity, Order order) {
        try {
            Criteria criteria = getSession().createCriteria(entity.getClass());
            criteria.add(Example.create(entity));
            if (order != null) {
                criteria.addOrder(order);
            }
            List list = criteria.list();
            if (list != null && list.size() > 0) {
                list.get(0);
            }
            return null;
        } catch (RuntimeException re) {
            throw re;
        }
    }
}
